/*******************************************************************************
* Copyright (c) 2015 Dominik Brämer.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
******************************************************************************/
package com.blogspot.thedsweb.gui;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.logging.Level;
import org.gnome.gdk.Event;
import org.gnome.gdk.Pixbuf;
import org.gnome.gtk.Align;
import org.gnome.gtk.Button;
import org.gnome.gtk.Frame;
import org.gnome.gtk.Gtk;
import org.gnome.gtk.HBox;
import org.gnome.gtk.HButtonBox;
import org.gnome.gtk.Label;
import org.gnome.gtk.Menu;
import org.gnome.gtk.MenuBar;
import org.gnome.gtk.MenuItem;
import org.gnome.gtk.MenuItem.Activate;
import org.gnome.gtk.SpinButton;
import org.gnome.gtk.Statusbar;
import org.gnome.gtk.Switch;
import org.gnome.gtk.VBox;
import org.gnome.gtk.Widget;
import org.gnome.gtk.Window;
import org.gnome.gtk.Window.DeleteEvent;
import org.gnome.gtk.WindowPosition;
import com.blogspot.thedsweb.main.Debug;
import com.blogspot.thedsweb.util.Check;
import com.blogspot.thedsweb.util.Config;
import com.blogspot.thedsweb.util.Database;
import com.blogspot.thedsweb.util.Files;
import com.blogspot.thedsweb.util.LockFile;
import com.blogspot.thedsweb.util.Translate;
public class MainGUI {
private static Window mainGUI;
private static Statusbar status;
private static Switch fdSwitch;
private static SpinButton llSpin;
private static SpinButton ulSpin;
private static SpinButton miInSpin;
private static SpinButton maInSpin;
private static SpinButton dtSpin;
private static SpinButton btSpin;
private static SpinButton loSpin;
private static Label minValue;
private static Label maxValue;
private static Label lastValue;
public MainGUI() {
mainGUI = new Window();
mainGUI.setSizeRequest(550, 0);
mainGUI.setResizable(false);
mainGUI.setTitle("Yawls");
mainGUI.setPosition(WindowPosition.CENTER);
mainGUI.setBorderWidth(5);
Pixbuf icon;
try {
icon = new Pixbuf(Database.PATH_ICON);
mainGUI.setIcon(icon);
} catch (final FileNotFoundException e) {
Debug.LOG.log(Level.WARNING, "Could not find yawls icon.");
}
status = new Statusbar();
final VBox ground = new VBox(false, 4);
// Create MenuBar
final MenuBar menuBar = new MenuBar();
constructMenu(menuBar);
final HBox cage = new HBox(false, 2);
final Frame frame1 = new Frame(null);
final Label stats = new Label("<b>" + Translate._("Webcam stats:")
+ "</b>");
stats.setUseMarkup(true);
frame1.setLabelWidget(stats);
constructWebcamStats(frame1);
frame1.setBorderWidth(1);
cage.add(frame1);
final Frame frame2 = new Frame(null);
final Label conf = new Label("<b>" + Translate._("Configuration:")
+ "</b>");
conf.setUseMarkup(true);
frame2.setLabelWidget(conf);
constructConfiguration(frame2);
frame2.setBorderWidth(1);
cage.add(frame2);
final HButtonBox buttonBox = new HButtonBox();
constructButton(buttonBox);
status.setMessage(checkStatus());
ground.packStart(menuBar, false, false, 0);
ground.packStart(cage, false, false, 0);
ground.packStart(buttonBox, false, false, 0);
ground.packEnd(status, false, false, 0);
mainGUI.add(ground);
mainGUI.connect(new DeleteEvent() {
@Override
public boolean onDeleteEvent(Widget arg0, Event arg1) {
Gtk.mainQuit();
return false;
}
});
}
public void start() {
mainGUI.showAll();
}
private String checkStatus() {
String status = "";
if (!Check.backlightDevice()) {
status = Translate._("No backlight device found");
if (!Check.camera()) {
status += " ";
return status + Translate._("and no camera found.");
}
status += ".";
} else if (!Check.camera()) {
return Translate._("No camera found.");
}
return status;
}
private void constructButton(HButtonBox buttonBox) {
final Button reset = new Button();
reset.setLabel(Translate._("Reset"));
reset.connect(new Button.Clicked() {
@Override
public void onClicked(Button arg0) {
Files.writeConfig();
readConfig();
}
});
buttonBox.add(reset);
final Button apply = new Button();
apply.setLabel(Translate._("Apply"));
apply.connect(new Button.Clicked() {
@Override
public void onClicked(Button arg0) {
final boolean fd = fdSwitch.isActive();
final int ll = (int) llSpin.getValue();
final int ul = (int) ulSpin.getValue();
final int mi = (int) miInSpin.getValue();
final int ma = (int) maInSpin.getValue();
final int dt = (int) dtSpin.getValue();
final int bt = (int) btSpin.getValue();
final int lo = (int) loSpin.getValue();
if (ul <= ll) {
status.setMessage(Translate
._("The value of the upper limit must be greater than the lower limit."));
return;
}
if (mi > ma) {
status.setMessage(Translate
._("The value of the max. increase must be greater than the min. increase."));
return;
}
status.setMessage(checkStatus());
final Properties config = new Properties();
config.setProperty("faceDetect", Boolean.toString(fd));
config.setProperty("lowerLimit", Integer.toString(ll));
config.setProperty("upperLimit", Integer.toString(ul));
config.setProperty("minIncrease", Integer.toString(mi));
config.setProperty("maxIncrease", Integer.toString(ma));
config.setProperty("darkeningThreshold", Integer.toString(dt));
config.setProperty("brighteningThreshold", Integer.toString(bt));
config.setProperty("logLevel", Integer.toString(lo));
final File cFile = new File(Database.PATH_TO_CONFIG_FILE);
try {
final OutputStream configStream = new FileOutputStream(
cFile);
config.store(configStream, "Yawls auto generated config");
} catch (final IOException e) {
Debug.LOG.log(Level.WARNING, "Could not create file: "
+ Database.PATH_TO_CONFIG_FILE, e);
}
// Create a lock file to trigger the daemon to
// reload the configuration on the fly
LockFile.create(Database.PATH_LOCK_CONFIG, false);
}
});
buttonBox.add(apply);
buttonBox.setAlignHorizontal(Align.END);
}
private void constructConfiguration(Frame frame) {
final VBox vbox = new VBox(false, 5);
vbox.setBorderWidth(10);
final HBox hbox1 = new HBox(true, 0);
hbox1.setSizeRequest(275, 0);
final HBox hbox2 = new HBox(true, 0);
hbox2.setSizeRequest(275, 0);
final HBox hbox3 = new HBox(true, 0);
hbox3.setSizeRequest(275, 0);
final HBox hbox4 = new HBox(true, 0);
hbox4.setSizeRequest(275, 0);
final HBox hbox5 = new HBox(true, 0);
hbox5.setSizeRequest(275, 0);
final HBox hbox6 = new HBox(true, 0);
hbox6.setSizeRequest(275, 0);
final HBox hbox7 = new HBox(true, 0);
hbox7.setSizeRequest(275, 0);
final HBox hbox8 = new HBox(true, 0);
hbox8.setSizeRequest(275, 0);
final Label fdLabel = new Label(Translate._("face detect"));
fdLabel.setAlignHorizontal(Align.START);
fdLabel.setTooltipText(Translate
._("Set true to enable or false to disable face detection"));
final Label llLabel = new Label(Translate._("lower limit"));
llLabel.setAlignHorizontal(Align.START);
llLabel.setTooltipText(Translate
._("Minimum time between camera activations in milliseconds"));
final Label ulLabel = new Label(Translate._("upper limit"));
ulLabel.setAlignHorizontal(Align.START);
ulLabel.setTooltipText(Translate
._("Maximum time between camera activations in milliseconds"));
final Label miInLabel = new Label(Translate._("min. increase"));
miInLabel.setAlignHorizontal(Align.START);
miInLabel
.setTooltipText(Translate
._("Minimum time increase between camera activations in milliseconds if nothing to do"));
final Label maInLabel = new Label(Translate._("max. increase"));
maInLabel.setAlignHorizontal(Align.START);
maInLabel
.setTooltipText(Translate
._("Maximum time increase between camera activations in milliseconds if nothing to do"));
final Label dtLabel = new Label(Translate._("darkening threshold"));
dtLabel.setAlignHorizontal(Align.START);
dtLabel.setTooltipText(Translate
._("Value for darkening threshold in percent (0-100)\nFor example a value of 25 means that the current brightness\nhas to be less than 75 percent of the last measured brightness."));
final Label btLabel = new Label(Translate._("brightening threshold"));
btLabel.setAlignHorizontal(Align.START);
btLabel.setTooltipText(Translate
._("Value for brightening threshold in percent (0-100)\nFor example a value of 10 means that the current brightness\nhas to be greater than 110 percent of the last measured brightness."));
final Label loLabel = new Label(Translate._("log level"));
loLabel.setAlignHorizontal(Align.START);
loLabel.setTooltipText(Translate
._("Log level 0 (error) < 1 (warning) < 2 (info) < 3 (debug)"));
hbox1.add(fdLabel);
hbox2.add(llLabel);
hbox3.add(ulLabel);
hbox4.add(miInLabel);
hbox5.add(maInLabel);
hbox6.add(dtLabel);
hbox7.add(btLabel);
hbox8.add(loLabel);
fdSwitch = new Switch();
fdSwitch.setAlignHorizontal(Align.START);
llSpin = new SpinButton(500, 600000, 500);
llSpin.setAlignHorizontal(Align.FILL);
ulSpin = new SpinButton(1000, 600000, 500);
ulSpin.setAlignHorizontal(Align.FILL);
miInSpin = new SpinButton(100, 600000, 100);
miInSpin.setAlignHorizontal(Align.FILL);
maInSpin = new SpinButton(100, 600000, 100);
maInSpin.setAlignHorizontal(Align.FILL);
dtSpin = new SpinButton(5, 100, 5);
dtSpin.setAlignHorizontal(Align.FILL);
btSpin = new SpinButton(5, 100, 5);
btSpin.setAlignHorizontal(Align.FILL);
loSpin = new SpinButton(0, 3, 1);
loSpin.setAlignHorizontal(Align.FILL);
readConfig();
hbox1.add(fdSwitch);
hbox2.add(llSpin);
hbox3.add(ulSpin);
hbox4.add(miInSpin);
hbox5.add(maInSpin);
hbox6.add(dtSpin);
hbox7.add(btSpin);
hbox8.add(loSpin);
vbox.packStart(hbox1, false, false, 0);
vbox.packStart(hbox2, false, false, 0);
vbox.packStart(hbox3, false, false, 0);
vbox.packStart(hbox4, false, false, 0);
vbox.packStart(hbox5, false, false, 0);
vbox.packStart(hbox6, false, false, 0);
vbox.packStart(hbox7, false, false, 0);
vbox.packStart(hbox8, false, false, 0);
frame.add(vbox);
}
private void constructWebcamStats(Frame frame) {
final VBox vbox = new VBox(false, 5);
vbox.setBorderWidth(10);
final HBox hbox1 = new HBox(true, 0);
final HBox hbox2 = new HBox(true, 0);
final HBox hbox3 = new HBox(true, 0);
final Label maxLabel = new Label(Translate._("Max. value:"));
final Label minLabel = new Label(Translate._("Min. value:"));
final Label lastLabel = new Label(Translate._("Last value:"));
maxValue = new Label();
minValue = new Label();
lastValue = new Label();
final Thread lastValueDaemon = new Thread(new ValueDaemon(minValue,
maxValue, lastValue), "valueDaemon");
lastValueDaemon.setDaemon(true);
lastValueDaemon.start();
hbox1.add(maxLabel);
hbox1.add(maxValue);
hbox2.add(minLabel);
hbox2.add(minValue);
hbox3.add(lastLabel);
hbox3.add(lastValue);
vbox.packStart(hbox1, false, false, 1);
vbox.packStart(hbox2, false, false, 1);
vbox.packStart(hbox3, false, false, 1);
frame.add(vbox);
}
private void readConfig() {
try {
final Config config = new Config();
fdSwitch.setActive(config.faceDetect());
llSpin.setValue(config.lowerLimit());
ulSpin.setValue(config.upperLimit());
miInSpin.setValue(config.minIncrease());
maInSpin.setValue(config.maxIncrease());
dtSpin.setValue(config.darkeningThreshold());
btSpin.setValue(config.brighteningThreshold());
loSpin.setValue(config.logLevel());
} catch (final MissingResourceException e) {
Debug.LOG.log(Level.SEVERE, "Could not find config file.", e);
} catch (final MalformedURLException e1) {
Debug.LOG.log(Level.SEVERE, "Could not read config file.", e1);
}
}
private void constructMenu(MenuBar menuBar) {
final MenuItem helpItem = new MenuItem(Translate._("_Help"));
final MenuItem prefItem = new MenuItem(Translate._("_Preferences"));
final Menu helpMenu = new Menu();
final Menu prefMenu = new Menu();
final MenuItem aboutItem = new MenuItem(Translate._("_About"));
final AboutGUI aboutGUI = new AboutGUI(mainGUI, aboutItem);
aboutGUI.start();
final MenuItem faqItem = new MenuItem(Translate._("FAQ"));
faqItem.connect(new Activate() {
@Override
public void onActivate(MenuItem arg0) {
// Open launchpad.net project questions web page
if (java.awt.Desktop.isDesktopSupported()) {
final java.awt.Desktop desktop = java.awt.Desktop
.getDesktop();
if (desktop.isSupported(java.awt.Desktop.Action.BROWSE)) {
java.net.URI uri;
try {
// Set URL for launchpad.net FAQ
uri = new java.net.URI(Database.QUESTIONS);
desktop.browse(uri);
} catch (final URISyntaxException e) {
Debug.LOG.log(Level.SEVERE, "Wrong URL syntax: "
+ Database.QUESTIONS, e);
} catch (final IOException e) {
Debug.LOG.log(Level.WARNING,
"Could not start default browser.", e);
}
}
}
}
});
final MenuItem calibItem = new MenuItem(Translate._("_Calibrate"));
final CalibGUI calibGUI = new CalibGUI(mainGUI, calibItem);
calibGUI.start();
helpMenu.add(aboutItem);
helpMenu.add(faqItem);
prefMenu.add(calibItem);
helpItem.setSubmenu(helpMenu);
prefItem.setSubmenu(prefMenu);
menuBar.add(helpItem);
menuBar.add(prefItem);
}
}